#include <cppcms/json.h>
#include <iostream>
#include <sstream>
#include "JSONParser.hpp"

using namespace netspy;

namespace cppcms {
    namespace json {

        //
        // We specilize cppcms::json::traits structure to convert
        // objects to and from json values
        //

        template<>
        struct traits<Message> {
            // this function should throw
            // cppcms::json::bad_value_cast in case
            // of invalid or impossible conversion, 
            // this would give an easy way to substitute
            // a default value in case of fault
            static Message get(value const &v)
            {
                Message message;
                if(v.type()!=is_object)
                    throw bad_value_cast();
                
                message.command=v.get<std::string>("command");
         	if (message.command.compare("register") == 0 )
		{
			
			if (v.find("payload.hash").type() == is_string)
			{
				message.info.hash = v.get<std::string>("payload.hash");
			}
			else if (v.find("payload.hash").type() == is_null)
			{
				message.info.hash = std::string("");
			}
			
		 	if (v.find("payload.port").type() == is_string)
			{
				message.info.port = atoi(v.get<std::string>("payload.port").c_str());
			}
			else
			{
				message.info.port = v.get<unsigned short>("payload.port");
			}		

			message.service_list =	v.get<std::vector<std::string> >("payload.service_list");
			return message;
		}
		else if (message.command.compare("check_status") == 0 )
		{
			std::vector<value> values = v.get<std::vector<value> >("payload.check_result");
			for(std::vector<value>::const_iterator it=values.begin(); it!=values.end(); it++)
			{
				   message.service_list.push_back((* (*it).object().begin()).first.str());
				   message.status_map.insert(std::make_pair((* (*it).object().begin()).first.str(),(* (*it).object().begin()).second.get_value<int>())); 

				
			}
		}	
                return message;
            }
            
		static void set(value &v, Message const &in)
        	{
                	v.set("command",in.command);
			if (in.command.compare("register") == 0)
			{
				v.set("payload.hash",in.info.hash);
				v.set("payload.status",in.info.status);
			}
			else if (in.command.compare("check_status") == 0)
			{
				
			}
        	}
        };
    } // json
} // cppcms

namespace netspy
{

Message JSONParser::unpack(const std::string &stringMessage)
{
	std::stringstream mess(stringMessage);
	cppcms::json::value object;
	object.load(mess,true);
	return object.get_value<Message>();
}

std::string JSONParser::pack(const Message &message)
{
	std::stringstream result;
	cppcms::json::value object = message;
	result << object;
	return result.str();
}



int json_test()
{
    cppcms::json::value my_object;
    cppcms::json::value inner_object;
    
    inner_object["hash"]="1";
    inner_object["status"]=0;
    inner_object["port"]=6666;
    inner_object["service_list"][0]="alive";
    inner_object["service_list"][1]="ftp";
    // Create object data
    my_object["command"]="register";
    my_object["payload"]=inner_object;
    // Get values using path.
    std::string name=my_object.get<std::string>("command");
    
    // load person object from the object
    // using above traits
    Message request = my_object.get_value<Message>();
   
    std::cout << "Req.command = " << request.command << std::endl;
    std::cout << "Req.info: hash = " << request.info.hash << " port = " << request.info.port << std::endl;
   std::cout << "Pack test: " << JSONParser::pack(request) << std::endl;
	 // save person object to json objectdd
    cppcms::json::value other = request;

    // write data to output
    std::cout << other << std::endl;

    // write data formatter nicely
    my_object.save(std::cout,cppcms::json::readable);

    // save object to stream and load it back
    std::stringstream tmp;
    tmp << my_object;
    cppcms::json::value reloaded;
    reloaded.load(tmp,true);
    return 0;
}
}
